/**
 * Copyright (C) 2008-2009 Cristian Olaru <colaru@gmail.com>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *         http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.integrationpath.mengine.webapp.listener;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.acegisecurity.providers.AuthenticationProvider;
import org.acegisecurity.providers.ProviderManager;
import org.acegisecurity.providers.dao.DaoAuthenticationProvider;
import org.acegisecurity.providers.encoding.PasswordEncoder;
import org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.compass.gps.CompassGps;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.integrationpath.mengine.service.LookupManager;
import com.integrationpath.mengine.webapp.util.EngineConstants;

/**
 * <p>StartupListener class used to initialize and database settings
 * and populate any application-wide drop-downs.
 * <p/>
 * <p>Keep in mind that this listener is executed outside of OpenSessionInViewFilter,
 * so if you're using Hibernate you'll have to explicitly initialize all loaded data at the
 * GenericDao or service level to avoid LazyInitializationException. Hibernate.initialize() works
 * well for doing this.
 *
 * @author <a href="mailto:colaru@gmail.com">Cristian Olaru</a>
 */
public class StartupListener implements ServletContextListener {
    private static final Log log = LogFactory.getLog(StartupListener.class);
    private static ServletContext appContext;

    public static ServletContext getAppContext() {
		return appContext;
	}

	public static void setAppContext(ServletContext appContext) {
		StartupListener.appContext = appContext;
	}

	@SuppressWarnings({"unchecked"})
    public void contextInitialized(ServletContextEvent event) {
        log.debug("Initializing context...");

        ServletContext context = event.getServletContext();
        appContext = context;
        
        // Orion starts Servlets before Listeners, so check if the config
        // object already exists
        Map<String, Object> config = (HashMap<String, Object>) context.getAttribute(EngineConstants.CONFIG);

        if (config == null) {
            config = new HashMap<String, Object>();
        }
        
        if (context.getInitParameter(EngineConstants.CSS_THEME) != null) {
            config.put(EngineConstants.CSS_THEME, context.getInitParameter(EngineConstants.CSS_THEME));
        }

        ApplicationContext ctx =
            WebApplicationContextUtils.getRequiredWebApplicationContext(context);

        PasswordEncoder passwordEncoder = null;
        try {
            ProviderManager provider = (ProviderManager) ctx.getBean("authenticationManager");
            for (Object o : provider.getProviders()) {
                AuthenticationProvider p = (AuthenticationProvider) o;
                if (p instanceof RememberMeAuthenticationProvider) {
                    config.put("rememberMeEnabled", Boolean.TRUE);
                } else if (p instanceof DaoAuthenticationProvider) {
                    passwordEncoder = ((DaoAuthenticationProvider) p).getPasswordEncoder();
                }
            }
        } catch (NoSuchBeanDefinitionException n) {
            log.debug("authenticationManager bean not found, assuming test and ignoring...");
            // ignore, should only happen when testing
        }

        context.setAttribute(EngineConstants.CONFIG, config);

        // output the retrieved values for the Init and Context Parameters
        if (log.isDebugEnabled()) {
            log.debug("Remember Me Enabled? " + config.get("rememberMeEnabled"));
            if (passwordEncoder != null) {
                log.debug("Password Encryptor: " + passwordEncoder.getClass().getName());
            }
            log.debug("Populating drop-downs...");
        }

        try {
        	log.info("StartupListener:contextInitialized - Load configuration file");
        	PropertiesConfiguration configBundle = new PropertiesConfiguration("ConfigurationResources.properties");
        	FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
        	// fileChangedReloadingStrategy.setRefreshDelay(6000);
			configBundle.setReloadingStrategy(fileChangedReloadingStrategy);
			context.setAttribute(EngineConstants.CONFIG_KEY, configBundle);
		} catch (ConfigurationException e) {
			log.error("StartupListener:contextInitialized - Problem in loading the application configuration file", e);
		}
        
        
        setupContext(context);
    }

    /**
     * This method uses the LookupManager to lookup available roles from the data layer.
     * @param context The servlet context
     */
    public static void setupContext(ServletContext context) {
        ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
        LookupManager mgr = (LookupManager) ctx.getBean("lookupManager");

        // get list of possible roles
        context.setAttribute(EngineConstants.AVAILABLE_ROLES, mgr.getAllRoles());
        log.debug("Drop-down initialization complete [OK]");
        // try to set a bundle for FMT        
//		ResourceBundle bundle = ResourceBundle.getBundle("DatabaseResources", new Locale("en", "en"), DbResourceBundle.getMyControl(context));
//		Config.set(context, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, new Locale("en", "en")));

        // start Compass index
        
        try {
			reindex(context);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    /**
     * Shutdown servlet context (currently a no-op method).
     *
     * @param servletContextEvent The servlet context event
     */
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        //LogFactory.release(Thread.currentThread().getContextClassLoader());
        //Commented out the above call to avoid warning when SLF4J in classpath.
        //WARN: The method class org.apache.commons.logging.impl.SLF4JLogFactory#release() was invoked.
        //WARN: Please see http://www.slf4j.org/codes.html for an explanation.
    }
    
	public static void reindex(ServletContext context) throws IOException {
		log.info("Enter Compass reIndex method");
		CompassGps compassGps = (CompassGps) getSpringContext(context).getBean(
				"compassGps");
		boolean isRun = compassGps.isRunning();
		log.info("Compass is running: " + isRun);
		if (!isRun)
			compassGps.start();
		compassGps.index();
	}
	
	static WebApplicationContext getSpringContext(ServletContext context) {
		return WebApplicationContextUtils.getWebApplicationContext(context);
	}
}
